package edu.cicese.alz.reports;

import edu.cicese.alz.FrameReport;
import edu.cicese.alz.Query;
import edu.cicese.alz.TimeUtil;
import edu.cicese.alz.swing.JNonEmptyTextField;
import edu.cicese.alz.swing.ScrollablePane;
import edu.cicese.alz.swing.SwingUtil;
import edu.cicese.alz.swing.calendar.TextFieldDateEditor;
import edu.cicese.alz.swing.dialogs.ErrorDialog;
import edu.cicese.alz.swing.tables.ScrollablePanel;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JRadioButton;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.ParseException;
import java.util.Date;
import java.util.TreeSet;

/**
 * Created by: Eduardo Quintana Contreras
 * Date: 3/07/12
 * Time: 12:06 PM
 */
public class ReportPane extends ScrollablePane {

	// User
	protected JRadioButton rbtUsersAll, rbtUsers;
	protected JNonEmptyTextField txtUsers;

	// Saving options
	protected JCheckBox chbShowCharts, chbSaveCharts;

	public static final int ACCELEROMETER = 1;
	public static final int GPS = 2;
	public static final int NFC = 3;
	public static final int WIFI = 4;

	protected static BlockCombinedPreview pCombinedPreview = new BlockCombinedPreview();

	public ReportPane() {
		txtUsers = SwingUtil.createNonEmptyTextField(100, 20);
		txtUsers.setDocument(FrameReport.txtUsersModel);
		txtUsers.getDocument().addDocumentListener(new UserDocumentListener());
		txtUsers.getDocument().addDocumentListener(new UsersEmptyTextListener(txtUsers));

		rbtUsersAll = SwingUtil.createRadioButton("All");
		rbtUsersAll.setModel(FrameReport.rbtUsersAllModel);

		rbtUsers = SwingUtil.createRadioButton("Users:");
		rbtUsers.setModel(FrameReport.rbtUsersModel);

		rbtUsers.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				checkUsersTextField(txtUsers);
			}
		});
		rbtUsersAll.addActionListener(new ActionListener() {
			@Override
			public void actionPerformed(ActionEvent e) {
				if (rbtUsersAll.isSelected() && txtUsers.hasError()) {
					txtUsers.setText("");
					rbtUsersAll.setSelected(true);
				}
				checkUsersTextField(txtUsers);
			}
		});
	}

	public void initOptionScrollPane(Box boxContent) {
		ScrollablePanel scrollablePanel = new ScrollablePanel(new BorderLayout());
		scrollablePanel.setScrollableWidth(ScrollablePanel.ScrollableSizeHint.STRETCH);
		scrollablePanel.setScrollableHeight(ScrollablePanel.ScrollableSizeHint.NONE);
		scrollablePanel.setScrollableBlockIncrement(
				ScrollablePanel.VERTICAL, ScrollablePanel.IncrementType.PERCENT, 200);

		boxContent.setBorder(BorderFactory.createLineBorder(Color.WHITE, 4));
		scrollablePanel.add(boxContent, BorderLayout.NORTH);
		scrollablePanel.setOpaque(false);

		setViewportView(scrollablePanel);
		setBackground(Color.WHITE);
		getViewport().setBackground(Color.WHITE);
		setBorder(BorderFactory.createLineBorder(Color.LIGHT_GRAY, 1));
		getVerticalScrollBar().setBorder(BorderFactory.createMatteBorder(2, 0, 2, 1, Color.WHITE));
		getVerticalScrollBar().setPreferredSize(new Dimension(17, Integer.MAX_VALUE));
		getHorizontalScrollBar().setBorder(BorderFactory.createMatteBorder(0, 2, 1, 2, Color.WHITE));
		getHorizontalScrollBar().setPreferredSize(new Dimension(Integer.MAX_VALUE, 17));
	}

	protected TreeSet<Integer> getUsers(JNonEmptyTextField txtUsers) {
		//TODO allow spaces
		boolean error = false;
		TreeSet<Integer> users = new TreeSet<>();
		String[] userGroups = txtUsers.getText().split(",");
		for (String userGroup : userGroups) {
			if (!userGroup.equals("")) {
				if (userGroup.contains("-")) {
					String[] userLimits = userGroup.split("-");
					if (userLimits.length == 2) {
						int userID1 = getUser(userLimits[0]);
						int userID2 = getUser(userLimits[1]);
						if (userID1 == userID2) {
							users.add(userID1);
						} else if (userID1 < userID2) {
							for (int userID = userID1; userID <= userID2; userID++) {
								users.add(userID);
							}
						} else {
							error = true;
						}
					} else {
						error = true;
					}
				} else {
					int userID = getUser(userGroup);
					if (userID != -1) {
						users.add(userID);
					} else {
						error = true;
					}
				}
			}
		}
		setTextFieldErrorFont(txtUsers, error);

		return users;
	}

	protected int getUser(String userString) {
		try {
			return Integer.parseInt(userString);
		} catch (NumberFormatException e) {
			return -1;
		}
	}

	protected TreeSet<Integer> getUsers() {
		TreeSet<Integer> users = new TreeSet<>();
		ResultSet resultSet = Query.executeQuery(Query.querySubjectIDs());
		try {
			while (resultSet.next()) {
				users.add(resultSet.getInt(1));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
		Query.close();

		return users;
	}

	public static Date[] getDates(int userID, int type) {
		Date[] dates = new Date[2];
		String query1, query2;
		switch (type) {
			case ACCELEROMETER:
				query1 = Query.queryAccelerometerFirstDate(userID);
				query2 = Query.queryAccelerometerLastDate(userID);
				break;
			case GPS:
				query1 = Query.queryGPSFirstDate(userID);
				query2 = Query.queryGPSLastDate(userID);
				break;
			case NFC:
				query1 = Query.queryNFCFirstDate(userID);
				query2 = Query.queryNFCLastDate(userID);
				break;
			default:
				query1 = Query.queryWIFIFirstDate(userID);
				query2 = Query.queryWIFILastDate(userID);
		}

		ResultSet resultSet = Query.executeQuery(query1);
		try {
			if (resultSet.next()) {
				dates[0] = TimeUtil.getDayTimestamp(resultSet.getLong(1)).getTime();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			Query.close();
		}
		resultSet = Query.executeQuery(query2);
		try {
			if (resultSet.next()) {
				dates[1] = TimeUtil.getDayTimestamp(resultSet.getLong(1)).getTime();
			}
		} catch (SQLException e) {
			e.printStackTrace();
		} finally {
			Query.close();
		}

		return dates;
	}

	protected Box createSavingBox() {
		chbShowCharts = SwingUtil.createCheckBox("Show charts");
		chbShowCharts.setModel(FrameReport.chbShowChart);
		chbSaveCharts = SwingUtil.createCheckBox("Save charts");
		chbSaveCharts.setModel(FrameReport.chbSaveChart);

		return createVerticalBox(new Component[]{
				chbShowCharts,
				chbSaveCharts
		}, leftMargin);
	}

	protected Box createUsersBox() {
		ButtonGroup rgUsers = new ButtonGroup();
		rgUsers.add(rbtUsersAll);
		rgUsers.add(rbtUsers);

		Box boxSpecifyUsers = createHorizontalBox(new Component[]{
				rbtUsers,
				Box.createHorizontalStrut(5),
				txtUsers,
				Box.createHorizontalStrut(5),
				new JLabel("(e.g. 1, 7, 10-22)")
		});

		return createVerticalBox(new Component[]{
				rbtUsersAll,
				boxSpecifyUsers
		}, leftMargin);
	}

	protected void showGenerateError() {
		new ErrorDialog(this, "Input error", ".");
	}

	protected void showLoadError() {
		new ErrorDialog(this, "Loading error", "An error occurred while loading saved options. Defaults restored.");
	}


	protected class DateDocumentListener implements DocumentListener {

		TextFieldDateEditor textField1, textField2;

		public DateDocumentListener(TextFieldDateEditor textField1, TextFieldDateEditor textField2) {
			this.textField1 = textField1;
			this.textField2 = textField2;
		}

		@Override
		public void insertUpdate(DocumentEvent e) {
			checkDates();
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			checkDates();
		}

		@Override
		public void changedUpdate(DocumentEvent e) {
			checkDates();
		}

		private void checkDates() {
			textField1.caretUpdate(null);
			textField2.caretUpdate(null);
			if (!textField1.hasFormatError() && !textField2.hasFormatError()) {
				Date date1, date2;
				try {
					date1 = SwingUtil.calendarDateFormat.parse(textField1.getText());
					textField2.setDateError(false);
				} catch (ParseException e) {
					return;
				}
				try {
					date2 = SwingUtil.calendarDateFormat.parse(textField2.getText());
				} catch (ParseException e) {
					return;
				}
				textField2.setDateError(date2.before(date1));
			} else if (textField1.hasFormatError() && !textField2.hasFormatError()) {
				textField2.setDateError(false);
			}
		}
	}

	class UserDocumentListener implements DocumentListener {

		@Override
		public void insertUpdate(DocumentEvent e) {
			checkUserInput();
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			checkUserInput();
		}

		@Override
		public void changedUpdate(DocumentEvent e) {
			checkUserInput();
		}

		private void checkUserInput() {
			rbtUsers.setSelected(true);
			getUsers(txtUsers);
		}
	}

	class UsersEmptyTextListener implements DocumentListener {
		private JNonEmptyTextField textField;

		public UsersEmptyTextListener(JNonEmptyTextField textField) {
			this.textField = textField;
		}

		@Override
		public void insertUpdate(DocumentEvent e) {
			checkText();
		}

		@Override
		public void removeUpdate(DocumentEvent e) {
			checkText();
		}

		@Override
		public void changedUpdate(DocumentEvent e) {
			checkText();
		}

		public void checkText() {
			checkUsersTextField(textField);
		}
	}


	private void checkUsersTextField(JNonEmptyTextField textField) {
		SwingUtil.checkEmptyTextField(textField, rbtUsers.isSelected());
	}

}
